#include "login.h"

#include <uuid/uuid.h>
#include <stdio.h>

#define LOGIN_VER1 0
#define LOGIN_VER2 1
#define REQ_BUF_LEN 128

bool check_request(char *buf){ // 验证报文消息头是否为请求登录
    uint16_t code = ntohs(*((uint16_t *)buf));
    return code == LOGIN_REQUEST;
}

bool check_version(char *buf){  // 验证报文消息头的版本号是否匹配
    uint8_t v1 = *((uint8_t *)(buf+2));
    uint8_t v2 = *((uint8_t *)(buf+3));
    return v1 == LOGIN_VER1 && v2 == LOGIN_VER2;
}

bool parse_login_info(char *buf, char *name, char *pwd){
    uint32_t msg_len = ntohl( *((uint32_t *)(buf+8)));
    if(msg_len <=0 ) return false;

    uint16_t name_len = ntohs( *((uint16_t *)(buf+12)) );  // 用户名的长度
    strncpy(name, buf+14, name_len); // 提取用户名

    uint16_t pwd_len = ntohs( *((uint16_t *)(buf+14+name_len)) );
    strncpy(pwd, buf+14+name_len+2, pwd_len); // 提取口令

    return true;
}

void make_token(char *token){
    uuid_t uuid;            // UUID 二进制格式
    char uuid_str[37];      // UUID 字符串格式（36字符 + '\0'）

    // 生成随机 UUID
    uuid_generate_random(uuid);

    // 将二进制 UUID 转换为字符串形式
    uuid_unparse(uuid, uuid_str);

    int j=0;
    for(int i=0;i<36;i++){
        if(uuid_str[i] != '-'){
            token[j++] = uuid_str[i];
        }
    }
}

Client_ * login_handle(int sockfd){
    struct sockaddr_in client;
    socklen_t client_len = sizeof(client);

    Client_ *c = (Client_ *)calloc(1, sizeof(Client_));

    c->fd = accept(sockfd, (struct sockaddr *) &client, &client_len);
    if(c->fd < 0){
        return NULL;
    }

    c->port = ntohs(client.sin_port);
    inet_ntop(AF_INET, &client.sin_addr.s_addr, c->ip, 16);

    // 日志（写入日志： 用户名， ip , login）
    return c;
}


char login_user_info[3][32]; // 登录成功的用户信息

void login_callback(char **cols, char **rowdata){
    // USER_ID
    for(int i=0;i<3;i++){  // i<3 查询语句中的列选择只有3列
        strncpy(login_user_info[i], rowdata[i], strlen(rowdata[i]));
    }
}


void response_login(int sockfd,char *request_buf, char *user_id, char *token){
    char buf[256] = "";
    strncpy(buf, request_buf, 8); // 复制请求报文中前8个字节
    *((uint16_t *)buf) = htons(2); // 修改消息头中的前2个字节为响应标识 2
    
    if(user_id){
        *((uint32_t *)(buf+8)) = 7+strlen(token);
        *((uint8_t *)(buf+12)) = 1; //登录成功
        
        strncpy(buf+13, user_id, 32); 
        *((uint16_t *)(buf+17)) = htons(32);

        strncpy(buf+19, token, 32); 
    }
    else {
        *((uint32_t *)(buf+8)) = 3+strlen(token);
        *((uint8_t *)(buf+12)) = 0; // 失败

        *((uint16_t *)(buf+13)) = htons(strlen(token)); // 错误信息
        strncpy(buf+15, token, strlen(token)); 
    }

    send(sockfd, buf, strlen(buf), 0);  // 发送数据
    
}

void save_token(char *user_id, char *token){
    char sql[128] = "";
    // 检查用户ID是否在其它已登录 ：后期完成
    sprintf(sql, "insert into User_Token(UserID,Token) values('%s', '%s')", user_id, token);
    insert_db(sql);
}

int login(Client_ *client){
    // 接收LOGIN请求数据报文
    char buf[REQ_BUF_LEN] = "";
    ssize_t len=recv(client->fd, buf, REQ_BUF_LEN, 0);
    if(len < 0) return -1;
    if(!(check_request(buf) && check_version(buf))) return -1;
    
    char name[32]="", pwd[32]="";
    parse_login_info(buf, name, pwd);

    // 数据库查询
    char sql[256]="";
    sprintf(sql, "select UserID,Phone,Role where UserName='%s' and aes_decrypt(unhex(PasswordHash),'!520@Disen')='%s'",name,pwd);

    if(!connect_db()){
        return -1;
    }
    if(query_db(sql, login_callback) > 0){
        // 登录成功, 写操作日志
        // 生成TOKEN
        char token[33] = "";
        make_token(token);

        // 保存token
        save_token(login_user_info[0], token);

        // 响应成功登录的数据
        response_login(client->fd, buf, login_user_info[0], token);
        return true;
    }
    
    response_login(client->fd, buf, NULL, "用户名或口令错误");

    close_db(); // 关闭数据库
    return false;
}
